package me.shiqiang.im.service;

import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.Producer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.tst.common.exception.ServiceException;
import com.tst.common.returnobj.BaseReturnObj;
import com.tst.common.returnobj.ReturnObjCode;
import com.tst.common.utils.DateUtils;
import com.tst.common.utils.JSONUtils;
import me.shiqiang.im.SnowFlake;
import me.shiqiang.im.dao.GroupDao;
import me.shiqiang.im.dao.UserGroupsDao;
import me.shiqiang.im.domain.*;
import me.shiqiang.im.enums.*;
import me.shiqiang.im.msg.MsgBody;
import me.shiqiang.im.redis.RedisKey;
//import me.shiqiang.im.repository.GroupChangeLogRepository;
import me.shiqiang.im.vo.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

//import javax.transaction.Transactional;
import java.util.*;


/**
 * @author cuishiqiang
 * @date 2017/12/8 下午6:46
 */
@Service
@CacheConfig(cacheManager = "GroupCacheManager", cacheNames = {"GROUP_CACHE"})
public class GroupService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    GroupDao groupDao;

    @Autowired
    UserGroupsDao userGroupsDao;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Value("${com.tst.rocketmq.producer.topic}")
    private String topic;

    @Value("${send.topic}")
    private String msgTopic;

    @Autowired
    @Qualifier("event")
    Producer producer;

    @Autowired
    @Qualifier("sender")
    Producer senderProducer;

    @Autowired
    SnowFlake snowFlake;


//    @Autowired
//    GroupChangeLogRepository groupChangeLogRepository;

    public Group get(Long groupId) {
        return groupDao.findOne(groupId);
    }

    public GroupVo getFormalizedGroup(Long groupId) {
        GroupVo groupVo = new GroupVo();
        Group group = groupDao.findOne(groupId);
        groupVo.setAvatar(group.getAvatar());
        groupVo.setAnnouncement(group.getAnnouncement());
        groupVo.setBackgroundImg(group.getBackgroundImg());
        groupVo.setGroupId(group.getGroupId());
        groupVo.setGroupName(group.getGroupName());
        groupVo.setMute(group.getMute());
        groupVo.setOwnerId(group.getOwnerId());
        groupVo.setType(group.getType());
        groupVo.setFromId(group.getFromId());
        List list = new ArrayList();
        for (GroupUser groupUser : group.getUsers().values()) {
            list.add(groupUser);
        }
        groupVo.setGroupUsers(list);

        return groupVo;
    }

//    @javax.transaction.Transactional
    public GroupChangeResultVo getGroup(Long groupId, long version) {
        //无论是否全量同步，先拿到当前版本，确保在拿group数据前客户端版本是准确or滞后的。
        Long currentVersion = versionGet(groupId);

        if (currentVersion == version) {
            return null;
        }
        Group group = groupDao.findOne(groupId);
        if (group == null) {
            return null;
        }

//        boolean incremental = isIncremental(group);
//        logger.info("incremental{}",incremental);
//        Map map = groupChangeLogRepository.getMinAndMaxVersionByGroupId(groupId);
//        Long minVersion = (Long) map.get("minVersion");
//        Long maxVersion = (Long) map.get("maxVersion");
//
//        if (null == minVersion || minVersion > version) {
//            incremental = false;
//        }
//        if (incremental) {
//            return getChangeResult(groupId, version, maxVersion);
//        }

        GroupChangeResultVo groupVo = new GroupChangeResultVo();
        groupVo.setAvatar(group.getAvatar());
        groupVo.setAnnouncement(group.getAnnouncement());
        groupVo.setBackgroundImg(group.getBackgroundImg());
        groupVo.setGroupId(group.getGroupId());
        groupVo.setGroupName(group.getGroupName());
        groupVo.setMute(group.getMute());
        groupVo.setOwnerId(group.getOwnerId());
        groupVo.setType(group.getType());
        groupVo.setFromId(group.getFromId());
        groupVo.setAnnouncementModifyUserId(group.getAnnouncementModifyUserId());
        groupVo.setAnnouncementModifyDate(group.getAnnouncementModifyDate());
        groupVo.setVersion(currentVersion);

        List list = new ArrayList();
        for (GroupUser groupUser : group.getUsers().values()) {
            list.add(groupUser);
        }
        groupVo.setChangedUsers(list);

        return groupVo;
    }

    public Long newGroup(NewGroupVo newGroupVo) {
        Group group = new Group();
        Long groupId = stringRedisTemplate.opsForValue().increment(RedisKey.GROUP_ID, 1);
        group.setGroupId(groupId);

        GroupProperties groupProperties = new GroupProperties();
        groupProperties.setGroupId(groupId);
        groupProperties.setType(newGroupVo.getType());
        groupProperties.setName(newGroupVo.getName());
        String[] userIdArray = new String[newGroupVo.getIds().size() + 1];

        GroupUser owner = new GroupUser();
        Long ownerId = newGroupVo.getCreateUserId();
        owner.setUserId(ownerId);
        owner.setMemberType(1);
        group.getUsers().put(ownerId, owner);
        group.setOwnerId(ownerId);
        UserGroups ownerUserGroups = userGroupsDao.findOne(ownerId);
        if (ownerUserGroups == null) {
            ownerUserGroups = new UserGroups();
            ownerUserGroups.setUserId(ownerId);
        }
        ownerUserGroups.getGroups().put(groupId, groupProperties);
        userGroupsDao.save(ownerUserGroups);

        int i = 0;
        for (Long userId : newGroupVo.getIds()) {
            userIdArray[i++] = userId.toString();
            GroupUser groupUser = new GroupUser();
            groupUser.setUserId(userId);
            group.getUsers().put(userId, groupUser);

            UserGroups userGroups = userGroupsDao.findOne(userId);
            if (userGroups == null) {
                userGroups = new UserGroups();
                userGroups.setUserId(userId);
            }
            userGroups.getGroups().put(groupId, groupProperties);
            userGroupsDao.save(userGroups);
        }
        userIdArray[i++] = newGroupVo.getCreateUserId().toString();
        groupDao.save(group);
        stringRedisTemplate.opsForSet().add(RedisKey.groupUserSet(groupId), userIdArray);
        sendMqMsg(groupId.toString());
        return group.getGroupId();
    }

//    @javax.transaction.Transactional
    public void addGroupUser(Long groupId, NewGroupVo newGroupVo) throws JsonProcessingException {
        Group group = groupDao.findOne(groupId);
        GroupProperties groupProperties = new GroupProperties();
        groupProperties.setGroupId(groupId);
        groupProperties.setType(group.getType());
        groupProperties.setName(groupProperties.getName());
        String[] userIdArray = new String[newGroupVo.getIds().size()];
        int i = 0;
//        boolean incremental = isIncremental(group);
//        if (group.getUsers().size() + newGroupVo.getIds().size() >= 50) {
//            incremental = true;
//        }
        for (Long userId : newGroupVo.getIds()) {
            userIdArray[i++] = userId.toString();
            GroupUser groupUser = new GroupUser();
            groupUser.setUserId(userId);
            group.getUsers().put(userId, groupUser);

            UserGroups userGroups = userGroupsDao.findOne(userId);
            if (userGroups == null) {
                userGroups = new UserGroups();
                userGroups.setUserId(userId);
            }
            userGroups.getGroups().put(groupId, groupProperties);
            userGroupsDao.save(userGroups);

//            if (incremental) {
//                GroupChangeLog groupChangeLog = new GroupChangeLog();
//                groupChangeLog.setGroupId(groupId);
//                groupChangeLog.setType(GroupChangeLogType.ADD_MEMBER);
//                groupChangeLog.setUserId(userId);
//                groupChangeLog.setValue(GroupChangeLogType.CHANGE_TYPE_MAP.get(GroupChangeLogType.ADD_MEMBER));
//                groupChangeLog.setVersion(versionIncrementAndGet(groupId));
//                groupChangeLog.setCreateDate(new Date());
//                groupChangeLogRepository.save(groupChangeLog);
//            }
        }
        groupDao.save(group);
//        if (!incremental) {
//            stringRedisTemplate.opsForSet().add(RedisKey.groupUserSet(groupId), userIdArray);
//            new Timer().schedule(new TimerTask() {
//                @Override
//                public void run() {
//                    try {
//                        sendAddMemberNotice(newGroupVo.getCreateUserId(), groupId, newGroupVo.getIds());
//                    } catch (JsonProcessingException e) {
//                        e.printStackTrace();
//                    }
//                }
//            }, 1000);
//        }
        sendMqMsg(groupId.toString());

    }

//    @javax.transaction.Transactional
    public BaseReturnObj deleteGroupUser(DeleteGroupUserVo vo) throws JsonProcessingException {
        Group group = groupDao.findOne(vo.getGroupId());
        Map<Long, GroupUser> groupUsers = group.getUsers();

        GroupUser manager = groupUsers.get(String.valueOf(vo.getManagerId()));
        String[] userIdArray = new String[vo.getTargetUserId().size()];
//        boolean incremental = isIncremental(group);
        try {
            for (int i = 0; i < vo.getTargetUserId().size(); i++ ) {
                Long id = vo.getTargetUserId().get(i);
                if (MemberType.OWNER.equals(manager.getMemberType()) || MemberType.ADMIN.equals(manager.getMemberType())) {
                    GroupUser targetUser = group.getUsers().get(String.valueOf(id));
                    if (targetUser == null) {
                        continue;
                    }
                    if (MemberType.OWNER.equals(targetUser.getMemberType()) || MemberType.ADMIN.equals(targetUser.getMemberType())) {
                        return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "不可踢出群管理员");
                    } else {
                        groupUsers.remove(String.valueOf(targetUser.getUserId()));
                        UserGroups userGroups = userGroupsDao.findOne(targetUser.getUserId());
                        userGroups.getGroups().remove(String.valueOf(vo.getGroupId()));
                        groupDao.save(group);
                        userGroupsDao.save(userGroups);
                        stringRedisTemplate.opsForSet().remove(RedisKey.groupUserSet(vo.getGroupId()), String.valueOf(id));
//                        if (incremental) {
//                            GroupChangeLog groupChangeLog = new GroupChangeLog();
//                            groupChangeLog.setGroupId(vo.getGroupId());
//                            groupChangeLog.setType(GroupChangeLogType.DEL_MEMBER);
//                            groupChangeLog.setUserId(id);
//                            groupChangeLog.setValue(GroupChangeLogType.CHANGE_TYPE_MAP.get(GroupChangeLogType.DEL_MEMBER));
//                            groupChangeLog.setVersion(versionIncrementAndGet(vo.getGroupId()));
//                            groupChangeLog.setCreateDate(new Date());
//                            groupChangeLogRepository.save(groupChangeLog);
//                        }
                    }
                } else {
                    return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "无权限踢出群成员");
                }
                userIdArray[i] = id.toString();
            }
            stringRedisTemplate.opsForSet().add(RedisKey.groupQuitUsers(vo.getGroupId()), userIdArray);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        }
        sendDelMemberNotice(vo.getManagerId(),vo.getGroupId(),vo.getTargetUserId());
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                sendMqMsg(vo.getGroupId().toString());
            }
        },1000);

        return new BaseReturnObj(ReturnObjCode.SUCCESS, "已踢出成员");
    }

    @Transactional
    public void quit(Long groupId, Long userId) throws JsonProcessingException {
        Group group = groupDao.findOne(groupId);

        GroupUser user = group.getUsers().get(String.valueOf(userId));
        if (user == null) {
            UserGroups userGroups = userGroupsDao.findOne(userId);
            userGroups.getGroups().remove(String.valueOf(groupId));
            userGroupsDao.save(userGroups);
            stringRedisTemplate.opsForSet().remove(RedisKey.groupUserSet(groupId), String.valueOf(userId));
            stringRedisTemplate.opsForSet().add(RedisKey.groupQuitUsers(groupId), String.valueOf(userId));
            return;
        }
//        boolean incremental = isIncremental(group);
        if (MemberType.OWNER.equals(user.getMemberType())) {
            Collection<GroupUser> groupUsers = group.getUsers().values();
            Long ownerId = null;
            for (GroupUser groupUser : groupUsers) {
                if (MemberType.ADMIN.equals(groupUser.getMemberType())) {
                    groupUser.setMemberType(MemberType.OWNER);
                    ownerId = groupUser.getUserId();
                    break;
                }
            }
            if (ownerId == null) {
                Iterator<GroupUser> iterator = group.getUsers().values().iterator();
                GroupUser newOwner = iterator.next();
                if (userId.equals(newOwner.getUserId())) {
                    if (iterator.hasNext()) {
                        newOwner = iterator.next();
                    } else {
                        newOwner = null;
                    }
                }
                if (newOwner != null) {
                    ownerId = newOwner.getUserId();
                    newOwner.setMemberType(MemberType.OWNER);
                }
            }
            group.setOwnerId(ownerId);
            groupDao.save(group);
        }
        group.getUsers().remove(String.valueOf(userId));
        if (group.getUsers().isEmpty()) {
            groupDao.delete(groupId);
        }else {
            groupDao.save(group);
        }

        UserGroups userGroups = userGroupsDao.findOne(userId);
        userGroups.getGroups().remove(String.valueOf(groupId));
        userGroupsDao.save(userGroups);
        stringRedisTemplate.opsForSet().remove(RedisKey.groupUserSet(groupId), String.valueOf(userId));

        stringRedisTemplate.opsForSet().add(RedisKey.groupQuitUsers(groupId), String.valueOf(userId));
//        if (incremental) {
//            GroupChangeLog groupChangeLog = new GroupChangeLog();
//            groupChangeLog.setGroupId(groupId);
//            groupChangeLog.setType(GroupChangeLogType.DEL_MEMBER);
//            groupChangeLog.setUserId(userId);
//            groupChangeLog.setValue(GroupChangeLogType.CHANGE_TYPE_MAP.get(GroupChangeLogType.DEL_MEMBER));
//            groupChangeLog.setVersion(versionIncrementAndGet(groupId));
//            groupChangeLog.setCreateDate(new Date());
//            groupChangeLogRepository.save(groupChangeLog);
//            sendMqMsg(groupId.toString());
//        }else {
            sendMemberQuitNotice(userId, groupId);
            new Timer().schedule(new TimerTask() {
                @Override
                public void run() {
                    sendMqMsg(groupId.toString());
                }
            }, 1000);
//        }
    }

    @Transactional
    public BaseReturnObj mute(Long groupId, Long userId) {
        Group group = groupDao.findOne(groupId);
        GroupUser groupUser = group.getUsers().get(String.valueOf(userId));
        if (!MemberType.OWNER.equals(groupUser.getMemberType()) && !MemberType.ADMIN.equals(groupUser.getMemberType())) {
            return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "无权限开启全员禁言");
        }
        group.setMute(1);
        groupDao.save(group);
//        boolean incremental = isIncremental(group);
//        if (incremental) {
//           headerIncremental(groupId);
//        }
        return new BaseReturnObj(ReturnObjCode.SUCCESS, "已开启全员禁言");
    }

    @Transactional
    public BaseReturnObj unmute(Long groupId, Long userId) {
        Group group = groupDao.findOne(groupId);
        GroupUser groupUser = group.getUsers().get(String.valueOf(userId));

        if (!MemberType.OWNER.equals(groupUser.getMemberType()) && !MemberType.ADMIN.equals(groupUser.getMemberType())) {
            return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "无权限解除全员禁言");
        }
        group.setMute(0);
        groupDao.save(group);
//        boolean incremental = isIncremental(group);
//        if (incremental) {
//            headerIncremental(groupId);
//        }
        return new BaseReturnObj(ReturnObjCode.SUCCESS, "已解除全员禁言");
    }


    @Transactional
    public BaseReturnObj modifyGroupName(ModifyGroupPropsVo vo) {
        Group group = groupDao.findOne(vo.getGroupId());
        GroupUser groupUser = group.getUsers().get(String.valueOf(vo.getUserId()));

        if (!MemberType.OWNER.equals(groupUser.getMemberType()) && !MemberType.ADMIN.equals(groupUser.getMemberType())) {
            return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "无权限修改群名");
        }
        group.setGroupName(vo.getName());
        groupDao.save(group);
//        boolean incremental = isIncremental(group);
//        if (incremental) {
//            headerIncremental(vo.getGroupId());
//        }
        return new BaseReturnObj(ReturnObjCode.SUCCESS, "已更换群名");
    }

    @Transactional
    public BaseReturnObj modifyGroupAvatar(ModifyGroupPropsVo vo) {
        Group group = groupDao.findOne(vo.getGroupId());
        GroupUser groupUser = group.getUsers().get(String.valueOf(vo.getUserId()));

        if (!MemberType.OWNER.equals(groupUser.getMemberType()) && !MemberType.ADMIN.equals(groupUser.getMemberType())) {
            return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "无权限修改群头像");
        }
        group.setAvatar(vo.getAvatar());
        groupDao.save(group);
//        boolean incremental = isIncremental(group);
//        if (incremental) {
//            headerIncremental(vo.getGroupId());
//        }
        return new BaseReturnObj(ReturnObjCode.SUCCESS, "已更换群头像");
    }

    @Transactional
    public BaseReturnObj modifyGroupAnnouncement(ModifyGroupPropsVo vo) {
        Group group = groupDao.findOne(vo.getGroupId());
        GroupUser groupUser = group.getUsers().get(String.valueOf(vo.getUserId()));

        if (!MemberType.OWNER.equals(groupUser.getMemberType()) && !MemberType.ADMIN.equals(groupUser.getMemberType())) {
            return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "无权限更改群公告");
        }
        group.setAnnouncement(vo.getAnnouncement());
        group.setAnnouncementModifyDate(DateUtils.format(new Date(), DateUtils.YYYY_MM_DD_HH_MM_SS.toPattern()));
        group.setAnnouncementModifyUserId(vo.getUserId());
        groupDao.save(group);
//        boolean incremental = isIncremental(group);
//        if (incremental) {
//            headerIncremental(vo.getGroupId());
//        }
        return new BaseReturnObj(ReturnObjCode.SUCCESS, "已更换群公告");
    }

    @Transactional
    public BaseReturnObj modifyGroupBgI(ModifyGroupPropsVo vo) {
        Group group = groupDao.findOne(vo.getGroupId());
        GroupUser groupUser = group.getUsers().get(String.valueOf(vo.getUserId()));

        if (!MemberType.OWNER.equals(groupUser.getMemberType()) && !MemberType.ADMIN.equals(groupUser.getMemberType())) {
            return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "无权限更改群聊背景图");
        }
        group.setBackgroundImg(vo.getBackgroundImg());
        groupDao.save(group);
//        boolean incremental = isIncremental(group);
//        if (incremental) {
//            headerIncremental(vo.getGroupId());
//        }
        return new BaseReturnObj(ReturnObjCode.SUCCESS, "已更换群聊背景图");
    }

    @Cacheable(key = "'groupUser.muted.cache'+#groupId + #userId")
    public boolean isMuted(Long groupId, Long userId) {
        Group group = groupDao.findOne(groupId);
        if (group == null) {
            return true;
        }
        GroupUser groupUser = group.getUsers().get(String.valueOf(userId));
        if (groupUser == null) {
            return true;
        }
        return MuteType.MUTED.equals(groupUser.getMute());
    }


    @Cacheable(key = "'groupUser.allMutedAndIsNormal.cache'+#groupId + #userId")
    public boolean allMutedAndIsNormal(Long groupId, Long userId) {
        Group group = groupDao.findOne(groupId);
        if (group == null) {
            return true;
        }
        GroupUser groupUser = group.getUsers().get(String.valueOf(userId));
        if (groupUser == null) {
            return true;
        }
        if (MuteType.MUTED.equals(group.getMute())) {
            return !MemberType.OWNER.equals(groupUser.getMute()) && !MemberType.ADMIN.equals(groupUser.getMute()) ;
        }
        return false;
    }

    @Transactional
    public BaseReturnObj unmute(Long groupId, Long userId, Long targetId) {
        logger.info("解除禁言");
        Group group = groupDao.findOne(groupId);
        GroupUser groupUser = group.getUsers().get(String.valueOf(userId));
        if (!MemberType.OWNER.equals(groupUser.getMemberType()) && !MemberType.ADMIN.equals(groupUser.getMemberType())) {
            return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "无权限解除禁言");
        }
        GroupUser target = group.getUsers().get(String.valueOf(targetId));
        target.setMute(MuteType.NOT_MUTED);
        groupDao.save(group);
//        boolean incremental = isIncremental(group);
//        if (incremental) {
//            GroupChangeLog groupChangeLog = new GroupChangeLog();
//            groupChangeLog.setGroupId(groupId);
//            groupChangeLog.setType(GroupChangeLogType.DISMISS_SINGLE_MUTE);
//            groupChangeLog.setUserId(userId);
//            groupChangeLog.setValue(GroupChangeLogType.CHANGE_TYPE_MAP.get(GroupChangeLogType.DISMISS_SINGLE_MUTE));
//            groupChangeLog.setVersion(versionIncrementAndGet(groupId));
//            groupChangeLog.setCreateDate(new Date());
//            groupChangeLogRepository.save(groupChangeLog);
//        }
        return new BaseReturnObj(ReturnObjCode.SUCCESS, "解除禁言成功");
    }

    @Transactional
    public BaseReturnObj mute(Long groupId, Long userId, Long targetId) {
        Group group = groupDao.findOne(groupId);
        GroupUser groupUser = group.getUsers().get(String.valueOf(userId));
        if (!MemberType.OWNER.equals(groupUser.getMemberType()) && !MemberType.ADMIN.equals(groupUser.getMemberType())) {
            return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "无权限禁言");
        }
        GroupUser target = group.getUsers().get(String.valueOf(targetId));
        target.setMute(MuteType.MUTED);
        groupDao.save(group);
//        boolean incremental = isIncremental(group);
//        if (incremental) {
//            GroupChangeLog groupChangeLog = new GroupChangeLog();
//            groupChangeLog.setGroupId(groupId);
//            groupChangeLog.setType(GroupChangeLogType.SINGLE_MUTE);
//            groupChangeLog.setUserId(userId);
//            groupChangeLog.setValue(GroupChangeLogType.CHANGE_TYPE_MAP.get(GroupChangeLogType.SINGLE_MUTE));
//            groupChangeLog.setVersion(versionIncrementAndGet(groupId));
//            groupChangeLog.setCreateDate(new Date());
//            groupChangeLogRepository.save(groupChangeLog);
//        }
        return new BaseReturnObj(ReturnObjCode.SUCCESS, "禁言成功");
    }

    @Transactional
    public BaseReturnObj assignAdmin(Long groupId, Long userId, Long targetId) {
        Group group = groupDao.findOne(groupId);
        GroupUser groupUser = group.getUsers().get(String.valueOf(userId));
        if (!MemberType.OWNER.equals(groupUser.getMemberType())) {
            return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "无权限赋予管理员身份");
        }
        GroupUser target = group.getUsers().get(String.valueOf(targetId));
        target.setMemberType(MemberType.ADMIN);
        groupDao.save(group);
//        boolean incremental = isIncremental(group);
//        if (incremental) {
//            GroupChangeLog groupChangeLog = new GroupChangeLog();
//            groupChangeLog.setGroupId(groupId);
//            groupChangeLog.setType(GroupChangeLogType.ASSIGN_ADMIN);
//            groupChangeLog.setUserId(userId);
//            groupChangeLog.setValue(GroupChangeLogType.CHANGE_TYPE_MAP.get(GroupChangeLogType.ASSIGN_ADMIN));
//            groupChangeLog.setVersion(versionIncrementAndGet(groupId));
//            groupChangeLog.setCreateDate(new Date());
//            groupChangeLogRepository.save(groupChangeLog);
//        }
        return new BaseReturnObj(ReturnObjCode.SUCCESS, "赋予管理员身份成功");
    }

    @Transactional
    public BaseReturnObj relieveAdmin(Long groupId, Long userId, Long targetId) {
        Group group = groupDao.findOne(groupId);
        GroupUser groupUser = group.getUsers().get(String.valueOf(userId));
        if (!MemberType.OWNER.equals(groupUser.getMemberType())) {
            return new BaseReturnObj(ReturnObjCode.BUSINESS_EXCEPTION, "无权限解除管理员身份");
        }
        GroupUser target = group.getUsers().get(String.valueOf(targetId));
        target.setMemberType(MemberType.MEMBER);
        groupDao.save(group);
//        boolean incremental = isIncremental(group);
//        if (incremental) {
//            GroupChangeLog groupChangeLog = new GroupChangeLog();
//            groupChangeLog.setGroupId(groupId);
//            groupChangeLog.setType(GroupChangeLogType.RELIEVE_ADMIN);
//            groupChangeLog.setUserId(userId);
//            groupChangeLog.setValue(GroupChangeLogType.CHANGE_TYPE_MAP.get(GroupChangeLogType.RELIEVE_ADMIN));
//            groupChangeLog.setVersion(versionIncrementAndGet(groupId));
//            groupChangeLog.setCreateDate(new Date());
//            groupChangeLogRepository.save(groupChangeLog);
//        }
        return new BaseReturnObj(ReturnObjCode.SUCCESS, "解除管理员身份成功");
    }

    @Transactional
    public BaseReturnObj setNickName(NickNameVo vo) {
        Group group = groupDao.findOne(vo.getGroupId());
        GroupUser groupUser = new GroupUser();
        groupUser.setUserId(vo.getUserId());
        groupUser.setNickName(vo.getNickName());
        group.getUsers().put(vo.getUserId(), groupUser);
        groupDao.save(group);
//        boolean incremental = isIncremental(group);
//        if (incremental) {
//            GroupChangeLog groupChangeLog = new GroupChangeLog();
//            groupChangeLog.setGroupId(vo.getGroupId());
//            groupChangeLog.setType(GroupChangeLogType.NICK_NAME_CHANGE);
//            groupChangeLog.setUserId(vo.getUserId());
//            groupChangeLog.setValue(GroupChangeLogType.CHANGE_TYPE_MAP.get(GroupChangeLogType.NICK_NAME_CHANGE));
//            groupChangeLog.setVersion(versionIncrementAndGet(vo.getGroupId()));
//            groupChangeLog.setCreateDate(new Date());
//            groupChangeLogRepository.save(groupChangeLog);
//        }
        return new BaseReturnObj(ReturnObjCode.SUCCESS, "更改昵称成功");
    }


    public void sendMqMsg(String body) {
        Message msg = new Message();
        msg.setTopic(topic);
        msg.setTag("group_change");
        msg.setBody(body.getBytes());
        producer.sendOneway(msg);
    }


    public void sendAddMemberNotice(Long optUserId,Long groupId,List<Long> userIds) throws JsonProcessingException {
        Long syncKey = snowFlake.nextId();
        Message msg = new Message();
        msg.setTopic(msgTopic);
        msg.setTag(MessageCType.GROUP);
        Properties properties = new Properties();
        properties.setProperty("to", groupId.toString());
        properties.setProperty("syncKey", syncKey.toString());
        msg.setUserProperties(properties);
        MsgBody msgBody = new MsgBody();
        msgBody.setSyncKey(snowFlake.nextId());
        msgBody.setFrom(optUserId);
        msgBody.setTo(groupId);
        msgBody.setcType(Integer.parseInt(MessageCType.GROUP));
        msgBody.setmType(Integer.parseInt(MessageMType.NOTICE));
        msgBody.setLocalId(0L);
        msgBody.setFromName("系统");
        msgBody.setAt(0);
        msgBody.setTs(System.currentTimeMillis());
        msgBody.setMsg("{\"type\":7,\"userIds\":"+ userIds.toString() +"}");
        msg.setBody(JSONUtils.toJSON(msgBody).getBytes());
        senderProducer.sendOneway(msg);
    }

    public void sendDelMemberNotice(Long optUserId,Long groupId,List<Long> userIds) throws JsonProcessingException {
        Long syncKey = snowFlake.nextId();
        Message msg = new Message();
        msg.setTopic(msgTopic);
        msg.setTag(MessageCType.GROUP);
        Properties properties = new Properties();
        properties.setProperty("to", groupId.toString());
        properties.setProperty("syncKey", syncKey.toString());
        msg.setUserProperties(properties);
        MsgBody msgBody = new MsgBody();
        msgBody.setSyncKey(syncKey);
        msgBody.setFrom(optUserId);
        msgBody.setTo(groupId);
        msgBody.setFromName("系统");
        msgBody.setAt(0);
        msgBody.setcType(Integer.parseInt(MessageCType.GROUP));
        msgBody.setmType(Integer.parseInt(MessageMType.NOTICE));
        msgBody.setLocalId(0L);
        msgBody.setTs(System.currentTimeMillis());
        msgBody.setMsg("{\"type\":8,\"userIds\":"+ userIds.toString() +"}");
        msg.setBody(JSONUtils.toJSON(msgBody).getBytes());
        senderProducer.sendOneway(msg);
    }

    public void sendMemberQuitNotice(Long optUserId,Long groupId) throws JsonProcessingException {
        Long syncKey = snowFlake.nextId();
        Message msg = new Message();
        msg.setTopic(msgTopic);
        msg.setTag(MessageCType.GROUP);
        Properties properties = new Properties();
        properties.setProperty("to", groupId.toString());
        properties.setProperty("syncKey", syncKey.toString());
        msg.setUserProperties(properties);
        MsgBody msgBody = new MsgBody();
        msgBody.setSyncKey(syncKey);
        msgBody.setFrom(optUserId);
        msgBody.setTo(groupId);
        msgBody.setFromName("系统");
        msgBody.setAt(0);
        msgBody.setcType(Integer.parseInt(MessageCType.GROUP));
        msgBody.setmType(Integer.parseInt(MessageMType.NOTICE));
        msgBody.setLocalId(0L);
        msgBody.setTs(System.currentTimeMillis());
        msgBody.setMsg("{\"type\":10}");
        msg.setBody(JSONUtils.toJSON(msgBody).getBytes());
        senderProducer.sendOneway(msg);
    }

    @CacheEvict(key = "'uid' + #userId  + 'session'+ #sessionId + 'ctype'+#ctype")
    public BaseReturnObj noDisturb(Long userId, Long sessionId, int ctype) {
        logger.info("设置免打扰");
        String noDisturbKey = RedisKey.noDisturKey(userId, sessionId, ctype);
        if (ctype == 2) {
            UserGroups userGroups = userGroupsDao.findOne(userId);
            if (userGroups == null) {
                throw new ServiceException("未找到该userGroups");
            }
            GroupProperties gp = userGroups.getGroups().get(String.valueOf(sessionId));
            if (gp == null) {
                throw new ServiceException("未找到该group");
            }
            gp.setNoDisturb(1);
            userGroupsDao.save(userGroups);
        }
        stringRedisTemplate.opsForValue().set(noDisturbKey, "1");

        return new BaseReturnObj(ReturnObjCode.SUCCESS, "设置免打扰成功");
    }

    @CacheEvict(key = "'uid' + #userId  + 'session'+ #sessionId + 'ctype'+#ctype")
    public BaseReturnObj cancelNoDisturb(Long userId, Long sessionId, int ctype) {
        logger.info("取消免打扰");
        String noDisturbKey = RedisKey.noDisturKey(userId, sessionId, ctype);
        if (ctype == 2) {
            UserGroups userGroups = userGroupsDao.findOne(userId);
            if (userGroups == null) {
                throw new ServiceException("未找到该userGroups");
            }
            GroupProperties gp = userGroups.getGroups().get(String.valueOf(sessionId));
            if (gp == null) {
                throw new ServiceException("未找到该group");
            }
            gp.setNoDisturb(0);
            userGroupsDao.save(userGroups);
        }
        stringRedisTemplate.opsForValue().set(noDisturbKey, "0");

        return new BaseReturnObj(ReturnObjCode.SUCCESS, "取消免打扰成功");
    }

    @Cacheable(key = "'uid' + #userId  + 'session'+ #sessionId + 'ctype'+#ctype")
    public boolean isNoDisturb(Long userId, Long sessionId, int ctype) {
        logger.info("从数据库查询是否免打扰");
        String noDisturbKey = RedisKey.noDisturKey(userId, sessionId, ctype);

        String muteValue = stringRedisTemplate.opsForValue().get(noDisturbKey);
        return NoDisturbType.NO_DISTURB.equals(muteValue);
    }

    public void deleteGroup(Long groupId) throws JsonProcessingException {
        Group group = groupDao.findOne(groupId);
        Map<Long, GroupUser> groupUsers = group.getUsers();
        logger.info(String.valueOf(group.getUsers().size()));
        for (GroupUser groupUser : groupUsers.values()) {
            Group cGroup = groupDao.findOne(groupId);
            groupUsers.remove(String.valueOf(cGroup.getUsers().get(groupUser.getUserId())));
            UserGroups userGroups = userGroupsDao.findOne(groupUser.getUserId());
            userGroups.getGroups().remove(String.valueOf(groupId));
            userGroupsDao.save(userGroups);
            groupDao.save(cGroup);
            stringRedisTemplate.opsForSet().remove(RedisKey.groupUserSet(groupId), groupUser.getUserId().toString());
            logger.info("已删除{}",groupUser.getUserId());
        }
        groupDao.delete(groupId);
        sendGroupDestroyNotice(groupId);
    }


    public void sendGroupDestroyNotice(Long groupId) throws JsonProcessingException {
        Long syncKey = snowFlake.nextId();
        Message msg = new Message();
        msg.setTopic(msgTopic);
        msg.setTag(MessageCType.GROUP);
        Properties properties = new Properties();
        properties.setProperty("to", groupId.toString());
        properties.setProperty("syncKey", syncKey.toString());
        msg.setUserProperties(properties);
        MsgBody msgBody = new MsgBody();
        msgBody.setSyncKey(syncKey);
        msgBody.setFrom(groupId);
        msgBody.setTo(groupId);
        msgBody.setFromName("系统");
        msgBody.setAt(0);
        msgBody.setcType(Integer.parseInt(MessageCType.GROUP));
        msgBody.setmType(Integer.parseInt(MessageMType.NOTICE));
        msgBody.setLocalId(0L);
        msgBody.setTs(System.currentTimeMillis());
        msgBody.setMsg("{\"type\":12}");
        msg.setBody(JSONUtils.toJSON(msgBody).getBytes());
        senderProducer.sendOneway(msg);
    }

//    public GroupChangeResultVo getChangeResult(Long groupId, Long version, Long maxVersion) {
//        Group group = groupDao.findOne(groupId);
//        if (group == null) {
//            throw new ServiceException("未找到该group");
//        }
//
//        List<GroupChangeLog> groupChangeLogs = groupChangeLogRepository.findByGroupIdAndVersionGreaterThanAndUserIdNotNull(groupId,version);
//
//        if (groupChangeLogs.isEmpty()) {
//            return null;
//        }
//
//        GroupChangeResultVo resultVo = new GroupChangeResultVo();
//        Map<Long, Integer> usersValue = new HashMap<>();
//        for (GroupChangeLog groupChangeLog : groupChangeLogs) {
//            int value = groupChangeLog.getValue();
//            if (usersValue.containsKey(groupChangeLog.getUserId())) {
//                value += usersValue.get(groupChangeLog.getUserId());
//            }else {
//                value = groupChangeLog.getValue();
//            }
//            usersValue.put(groupChangeLog.getUserId(), value);
//        }
//        List<GroupUser> groupUsers = new ArrayList<>();
//        List<Long> quitUsers = new ArrayList<>();
//        for (Map.Entry<Long, Integer> entry : usersValue.entrySet()) {
//            if (entry.getValue() >= 0) {
//                GroupUser user = group.getUsers().get(String.valueOf(entry.getKey()));
//                groupUsers.add(user);
//            }else {
//                quitUsers.add(entry.getKey());
//            }
//        }
//
//        resultVo.setGroupId(group.getGroupId());
//        resultVo.setGroupName(group.getGroupName());
//        resultVo.setOwnerId(group.getOwnerId());
//        resultVo.setAvatar(group.getAvatar());
//        resultVo.setAnnouncement(group.getAnnouncement());
//        resultVo.setAnnouncementModifyUserId(group.getAnnouncementModifyUserId());
//        resultVo.setAnnouncementModifyDate(group.getAnnouncementModifyDate());
//        resultVo.setType(group.getType());
//        resultVo.setMute(group.getMute());
//        resultVo.setFromId(group.getFromId());
//        resultVo.setBackgroundImg(group.getBackgroundImg());
//
//        resultVo.setVersion(maxVersion);
//
//
//        resultVo.setChangedUsers(groupUsers);
//        resultVo.setDeletedUsers(quitUsers);
//
//        return resultVo;
//    }

//    private Boolean isIncremental(Group group) {
//        boolean incremental = false;
//        if (group.getUsers().size() >= 50) {
//            incremental = true;
//        }else {
//            Long version = groupChangeLogRepository.getMinimumVersionByGroupId(group.getGroupId());
//            if (null != version) {
//                incremental = true;
//            }
//        }
//        return incremental;
//    }

    public Long versionIncrementAndGet(Long groupId) {
       return stringRedisTemplate.opsForValue().increment("ver" + groupId, 1);
    }

    public Long versionGet(Long groupId) {
        return Long.valueOf(stringRedisTemplate.opsForValue().get("ver" + groupId));
    }


//    @Transactional
//    public void saveIncrementalLog(GroupChangeLogVo groupChangeLogVo) {
//        GroupChangeLog groupChangeLog = new GroupChangeLog();
//        groupChangeLog.setGroupId(groupChangeLogVo.getGroupId());
//        groupChangeLog.setType(groupChangeLogVo.getType());
//        groupChangeLog.setValue(groupChangeLogVo.getValue());
//        groupChangeLog.setUserId(groupChangeLogVo.getUserId());
//        groupChangeLog.setVersion(groupChangeLogVo.getVersion());
//        groupChangeLog.setCreateDate(new Date());
//        groupChangeLogRepository.save(groupChangeLog);
//    }
//
//    private void headerIncremental(Long groupId) {
//        GroupChangeLog groupChangeLog = new GroupChangeLog();
//        groupChangeLog.setGroupId(groupId);
//        groupChangeLog.setType(GroupChangeLogType.HEADER_CHANGE);
//        groupChangeLog.setValue(GroupChangeLogType.CHANGE_TYPE_MAP.get(GroupChangeLogType.HEADER_CHANGE));
//        groupChangeLog.setVersion(versionIncrementAndGet(groupId));
//        groupChangeLog.setCreateDate(new Date());
//        groupChangeLogRepository.save(groupChangeLog);
//    }

    public Long newGroup(NewServiceGroupVo newGroupVo) {
        String existGroupId = (String) stringRedisTemplate.opsForHash().get(RedisKey.SERVICE_PLATFORM + newGroupVo.getCreateUserId(), String.valueOf(newGroupVo.getPlatformType()));
        if (org.apache.commons.lang3.StringUtils.isNotBlank(existGroupId)) {
            return Long.valueOf(existGroupId);
        }
        Group group = new Group();
        Long groupId = stringRedisTemplate.opsForValue().increment(RedisKey.GROUP_ID, 1);
        group.setGroupId(groupId);

        GroupProperties groupProperties = new GroupProperties();
        groupProperties.setGroupId(groupId);
        groupProperties.setType(newGroupVo.getType());
        groupProperties.setName(newGroupVo.getName());
        groupProperties.setPlatformType(newGroupVo.getPlatformType());
        String[] userIdArray = new String[newGroupVo.getStaffs().size() + 1];

        GroupUser owner = new GroupUser();
        Long ownerId = newGroupVo.getCreateUserId();
        owner.setUserId(ownerId);
        owner.setMemberType(0);
        group.getUsers().put(ownerId, owner);
        group.setOwnerId(ownerId);
        group.setServicePlatformType(newGroupVo.getPlatformType());
        group.setType(newGroupVo.getType());
        group.setGroupName(newGroupVo.getName());
        UserGroups ownerUserGroups = userGroupsDao.findOne(ownerId);
        if (ownerUserGroups == null) {
            ownerUserGroups = new UserGroups();
            ownerUserGroups.setUserId(ownerId);
        }
        ownerUserGroups.getGroups().put(groupId, groupProperties);
        userGroupsDao.save(ownerUserGroups);

        int i = 0;
        for (CustomerServiceStaff staff : newGroupVo.getStaffs()) {
            Long userId = staff.getId();
            userIdArray[i++] = userId.toString();
            GroupUser groupUser = new GroupUser();
            groupUser.setUserId(userId);
            groupUser.setNickName(staff.getName());
            group.getUsers().put(userId, groupUser);

            UserGroups userGroups = userGroupsDao.findOne(userId);
            if (userGroups == null) {
                userGroups = new UserGroups();
                userGroups.setUserId(userId);
            }
            userGroups.getGroups().put(groupId, groupProperties);
            userGroupsDao.save(userGroups);
        }
        userIdArray[i++] = newGroupVo.getCreateUserId().toString();
        groupDao.save(group);
        stringRedisTemplate.opsForSet().add(RedisKey.groupUserSet(groupId), userIdArray);
        sendMqMsg(groupId.toString());
        stringRedisTemplate.opsForSet().add(RedisKey.SERVICE_PLATFORM + newGroupVo.getPlatformType(), groupId.toString());
        stringRedisTemplate.opsForHash().put(RedisKey.SERVICE_PLATFORM + newGroupVo.getCreateUserId(),String.valueOf(newGroupVo.getPlatformType()), groupId.toString());
        return groupId;
    }




    public List getAllGroupInfoByPlatformId(Long platformId) {
        Set<String> groupIds = stringRedisTemplate.opsForSet().members(RedisKey.SERVICE_PLATFORM + platformId);
        List<GroupVo> resultList = new ArrayList<>();
        for (String groupId : groupIds) {
            GroupVo groupVo = new GroupVo();
            Group group = groupDao.findOne(Long.valueOf(groupId));
            if (group == null) {
                continue;
            }
            groupVo.setAvatar(group.getAvatar());
            groupVo.setAnnouncement(group.getAnnouncement());
            groupVo.setBackgroundImg(group.getBackgroundImg());
            groupVo.setGroupId(group.getGroupId());
            groupVo.setGroupName(group.getGroupName());
            groupVo.setMute(group.getMute());
            groupVo.setOwnerId(group.getOwnerId());
            groupVo.setType(group.getType());
            groupVo.setFromId(group.getFromId());
            List list = new ArrayList();
            for (GroupUser groupUser : group.getUsers().values()) {
                list.add(groupUser);
            }
            groupVo.setGroupUsers(list);

            resultList.add(groupVo);
        }
        return resultList;
    }
}
